//! System call execution context
//! SPDX-License-Identifier: MPL-2.0

const std = @import("std");

/// Process ID type
pub const Pid = i32;

/// Thread ID type  
pub const Tid = i32;

/// File descriptor type
pub const Fd = i32;

/// Virtual address type
pub const VirtAddr = u64;

/// Physical address type
pub const PhysAddr = u64;

/// User space memory access interface
pub const UserSpace = struct {
    base_addr: VirtAddr,
    size: usize,
    
    const Self = @This();
    
    pub fn init(base: VirtAddr, size: usize) Self {
        return Self{
            .base_addr = base,
            .size = size,
        };
    }
    
    /// Create a reader for user space memory
    pub fn reader(self: Self, addr: VirtAddr, len: usize) !UserSpaceReader {
        if (addr < self.base_addr or addr + len > self.base_addr + self.size) {
            return error.InvalidAddress;
        }
        return UserSpaceReader.init(addr, len);
    }
    
    /// Create a writer for user space memory
    pub fn writer(self: Self, addr: VirtAddr, len: usize) !UserSpaceWriter {
        if (addr < self.base_addr or addr + len > self.base_addr + self.size) {
            return error.InvalidAddress;
        }
        return UserSpaceWriter.init(addr, len);
    }
    
    /// Read bytes from user space
    pub fn read_bytes(self: Self, addr: VirtAddr, buffer: []u8) !usize {
        _ = self;
        // TODO: Implement actual user space memory access
        // This is a placeholder that would need to be implemented
        // with proper page table walking and memory protection checks
        const src: [*]const u8 = @ptrFromInt(addr);
        @memcpy(buffer, src[0..buffer.len]);
        return buffer.len;
    }
    
    /// Write bytes to user space
    pub fn write_bytes(self: Self, addr: VirtAddr, data: []const u8) !usize {
        _ = self;
        // TODO: Implement actual user space memory access
        const dst: [*]u8 = @ptrFromInt(addr);
        @memcpy(dst[0..data.len], data);
        return data.len;
    }
    
    /// Copy string from user space
    pub fn copy_string(self: Self, addr: VirtAddr, buffer: []u8) ![]u8 {
        var i: usize = 0;
        while (i < buffer.len - 1) {
            const byte_addr = addr + i;
            if (byte_addr >= self.base_addr + self.size) {
                return error.InvalidAddress;
            }
            
            const byte_ptr: *const u8 = @ptrFromInt(byte_addr);
            const byte = byte_ptr.*;
            buffer[i] = byte;
            
            if (byte == 0) {
                return buffer[0..i];
            }
            i += 1;
        }
        buffer[buffer.len - 1] = 0;
        return buffer[0..buffer.len-1];
    }
};

/// User space memory reader
pub const UserSpaceReader = struct {
    addr: VirtAddr,
    len: usize,
    pos: usize,
    
    const Self = @This();
    
    pub fn init(addr: VirtAddr, len: usize) Self {
        return Self{
            .addr = addr,
            .len = len,
            .pos = 0,
        };
    }
    
    pub fn read(self: *Self, buffer: []u8) !usize {
        const remaining = self.len - self.pos;
        const to_read = @min(buffer.len, remaining);
        
        if (to_read == 0) return 0;
        
        // TODO: Implement proper user space access
        const src: [*]const u8 = @ptrFromInt(self.addr + self.pos);
        @memcpy(buffer[0..to_read], src[0..to_read]);
        
        self.pos += to_read;
        return to_read;
    }
    
    pub fn read_all(self: *Self, buffer: []u8) !void {
        if (buffer.len != self.len - self.pos) {
            return error.InvalidLength;
        }
        _ = try self.read(buffer);
    }
};

/// User space memory writer
pub const UserSpaceWriter = struct {
    addr: VirtAddr,
    len: usize,
    pos: usize,
    
    const Self = @This();
    
    pub fn init(addr: VirtAddr, len: usize) Self {
        return Self{
            .addr = addr,
            .len = len,
            .pos = 0,
        };
    }
    
    pub fn write(self: *Self, data: []const u8) !usize {
        const remaining = self.len - self.pos;
        const to_write = @min(data.len, remaining);
        
        if (to_write == 0) return 0;
        
        // TODO: Implement proper user space access
        const dst: [*]u8 = @ptrFromInt(self.addr + self.pos);
        @memcpy(dst[0..to_write], data[0..to_write]);
        
        self.pos += to_write;
        return to_write;
    }
    
    pub fn write_all(self: *Self, data: []const u8) !void {
        if (data.len != self.len - self.pos) {
            return error.InvalidLength;
        }
        _ = try self.write(data);
    }
};

/// Thread-local storage
pub const ThreadLocal = struct {
    tid: Tid,
    file_table: *FileTable,
    signal_mask: u64,
    
    const Self = @This();
    
    pub fn init(tid: Tid, file_table: *FileTable) Self {
        return Self{
            .tid = tid,
            .file_table = file_table,
            .signal_mask = 0,
        };
    }
    
    pub fn borrow_file_table_mut(self: *Self) *FileTable {
        return self.file_table;
    }
};

/// Process context
pub const ProcessContext = struct {
    pid: Pid,
    parent_pid: Pid,
    user_id: u32,
    group_id: u32,
    working_dir: []const u8,
    
    const Self = @This();
    
    pub fn init(pid: Pid, parent_pid: Pid) Self {
        return Self{
            .pid = pid,
            .parent_pid = parent_pid,
            .user_id = 0,
            .group_id = 0,
            .working_dir = "/",
        };
    }
};

/// File table (placeholder)
pub const FileTable = struct {
    // TODO: Implement file table
    dummy: u32,
    
    pub fn init() FileTable {
        return FileTable{ .dummy = 0 };
    }
};

/// Main system call execution context
pub const Context = struct {
    thread_local: ThreadLocal,
    process: ProcessContext,
    user_space_info: UserSpace,
    
    const Self = @This();
    
    pub fn init(
        tid: Tid,
        pid: Pid,
        parent_pid: Pid,
        file_table: *FileTable,
        user_base: VirtAddr,
        user_size: usize,
    ) Self {
        return Self{
            .thread_local = ThreadLocal.init(tid, file_table),
            .process = ProcessContext.init(pid, parent_pid),
            .user_space_info = UserSpace.init(user_base, user_size),
        };
    }
    
    /// Get user space interface
    pub fn user_space(self: *const Self) UserSpace {
        return self.user_space_info;
    }
    
    /// Get current process ID
    pub fn current_pid(self: *const Self) Pid {
        return self.process.pid;
    }
    
    /// Get current thread ID
    pub fn current_tid(self: *const Self) Tid {
        return self.thread_local.tid;
    }
    
    /// Get current user ID
    pub fn current_uid(self: *const Self) u32 {
        return self.process.user_id;
    }
    
    /// Get current group ID
    pub fn current_gid(self: *const Self) u32 {
        return self.process.group_id;
    }
    
    /// Check if current process has capability
    pub fn has_capability(self: *const Self, capability: u32) bool {
        _ = self;
        _ = capability;
        // TODO: Implement capability checking
        return false;
    }
    
    /// Get working directory
    pub fn get_working_dir(self: *const Self) []const u8 {
        return self.process.working_dir;
    }
};